/**
 * Author: Void rangers
 * Date: 2022.4.24
 * Version: 1.4.1
 * Description: multilevel linkage that depends on the SELECT component.
 */
;
!function($, win){
    function Linkage(ele, opt){
        this.$ele = ele;
        this.defaults = {
            debug: true,
            doms: [],
            list: [],
            change: [],
            labelKey: 'text',  //option内容的键名
            valueKey: 'value',  //select值的键名
            childrenKey: 'children',    //children子类的键名
            defaultValue: [],   //默认值
            html: $('<option></option>'),
            noneMore: true,               //没有子类时的操作 (false: 不执行默认操作, true: 执行, 可以为自定义函数)
            beforeCreate: function(){},   //列表挂载前
            updateBefore: function(){},   //已选择，但未更新联动数据
            updateAfter: function(){}     //已选择，已更新联动数据
        };
        this.options = $.extend({}, this.defaults, opt);
    }
    Linkage.prototype = {
        init: function(){
            var _this = this,
                opts = _this.options;
            for(var i = 0; i < opts.doms.length; i++){
                $(opts.doms[i]).attr('data-type', i);
                opts.change[i] = 0;
            }
            if(this.options.debug) console.log('linkage Start:', this);

            if(Array.isArray(opts.defaultValue)){
                if(opts.defaultValue.length > 0) this.getMatching(opts.list, 0);
            }else{
                throw new Error("默认值必须以数组形式，无默认值可填空。")
            }
            if(!opts.defaultValue || opts.defaultValue.length == 0) this.selectCity();

            //选择
            _this.$ele.on('change', opts.doms.join(', '), function(e){
                var $this = $(this),
                    type = $this.data('type'),
                    index = $this.find('option:selected').data('idx');
                for(var i in opts.change){
                    if(i == type) opts.change[type] = index;
                    if(i > type) opts.change[i] = 0;
                }
                opts.defaultValue = false;
                _this.selectCity(type, index, $this);
                // console.log('change:', type, index, opts.change);
            })
        },
        getMatching(list, i){
            let opts = this.options,
                val = opts.defaultValue[i];
            for(var key in list){
                let item = list[key];
                // console.log('matching:', item[opts.valueKey], ' | ', val);
                if(item[opts.valueKey] == val){
                    opts.change[i] = key;
                    this.$ele.find(opts.doms[i]).val(val);
                    // console.log(`val(${i}):`, val);
                    break;
                }
            }
            if(opts.defaultValue.length > i + 1){
                this.getMatching(list[opts.change[i]][opts.childrenKey], i + 1);
            } else {
                // console.log('change:', this.options.change);
                this.selectCity();
            }
        },
        /**
         * @param type  {Number}    级别
        */
        selectCity: function(type = -1, dom){
            var _this = this,
                list = null,
                opts = this.options;
            // console.log('select:', type,);
            if(typeof opts.updateBefore == 'function'){
                if(dom) opts.updateBefore.bind($.extend(opts, {ele: dom}))();
            } else {
                throw new Error('updateBefore is not a function.');
            }
            // 选择后，后续联动的参数change没有归零
            for(var i in opts.change){
                let parent = list ? list[opts.change[i - 1]] : {};
                list = list ? list[opts.change[i - 1]][opts.childrenKey] : opts.list;
                if(!list) throw new Error("多级联动数据中的子类不能为空!");
                if(list.length == 0){
                    if(opts.noneMore){
                        if(typeof opts.noneMore == 'function'){
                            opts.noneMore($(opts.doms.slice(i).join(', ')), {
                                doms: $(opts.doms.join(', ')),
                                key: i
                            });
                        } else {
                            $(opts.doms.join(', ')).show();
                            //由于是后一次循环，更新前一次的数据，所以最后一次循环取消判断
                            if(i < opts.change.length - 1) $(opts.doms.slice(i).join(', ')).hide();
                        }
                    }
                    break;
                }
                if(typeof opts.beforeCreate == 'function'){
                    let p = {
                        level: Number(i),
                        ...parent
                    };
                    delete p[opts.childrenKey];
                    list = opts.beforeCreate(list, p) || list;
                } else {
                    throw new Error('updateBefore is not a function.');
                }
                // list.unshift({text:'全部', value:0, children: []});
                if(i <= type) continue; //手动选择的时候，更新所选项后面的子类
                _this.createHtml(list, i, parent);
                // console.log(`SC list(${i}):`, list, '\n', i + ': ', opts.change); //return false;
            }
            // console.log(`list:`, list);
            // console.log('opts:', opts);
            // console.log('options:', this.options);
            if(typeof opts.updateAfter == 'function'){
                if(dom) opts.updateAfter.bind($.extend(opts, {ele: dom}))();
            } else {
                throw new Error('updateAfter is not a function.');
            }
        },
        createHtml: function(list, key, parent){
            var opts = this.options,
                $dom = this.$ele.find(opts.doms[key]);
            if(!this.options.reserve) $dom.html('');
            // console.log(`html(${key}): `, list, $dom);
            list.map((item, i) => {
                let $h = opts.html.clone();
                $h.text(item[opts.labelKey]).val(item[opts.valueKey]).attr('data-idx', i);
                // console.log(`defaultValue(${key}):`, opts.defaultValue[key], ' | ', v[opts.valueKey]);
                if(opts.defaultValue && opts.defaultValue[key] == item[opts.valueKey]){
                    //若无默认值，会默认获取第一个为选中项
                    $h.prop('selected', true);
                }
                $dom.append($h);
            })
        }
    };
    $.fn.linkage = function(options){
        var linkage = new Linkage(this, options);
        if(linkage.options.debug) win.linkage = linkage;
        linkage.init();
        return this;
    }
}(jQuery, window);